package com.codeyang.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.codeyang.constant.CategoryConstant;
import com.codeyang.domain.Category;
import com.codeyang.mapper.CategoryMapper;
import com.codeyang.service.CategoryService;
import com.codeyang.vo.CategoryVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
 * 描述: TO-删除标志-DO
 *
 * @author CodeYang_Site
 * @version 2021/5/24 22:34
 */
// 配置 缓存前置名称
@CacheConfig(cacheNames = "com.codeyang.service.impl.CategoryServiceImpl")
@Service
@Slf4j
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {


    @Autowired
    private CategoryMapper categoryMapper;

    /**
     * 使用集成的cache的缓存.
     * 1.代码方式的缓存 逻辑性好 但是逻辑性大
     * 2.使用注解方式的缓存 这样可卸载比较方便
     * 3.注意 缓存设置后,应该在 "修改" 后删除或者更新缓存 delete put
     * 注意:
     * key的操作是支持 SPEL表达式的,但是使用常量必须使用 '' 所以定义的常量也必须使用''
     *
     * @return
     */
    @Cacheable(key = CategoryConstant.CATEGORY_PREFIX)
    @Override
    public List<Category> list() {

        List<Category> categoryList = categoryMapper.selectList(
                new LambdaQueryWrapper<Category>()
                        .orderByDesc(Category::getSeq));
        return categoryList;
    }

    /**
     * 查询所有商品的父亲分类
     *
     * @return
     */
    @Cacheable(key = CategoryConstant.CATEGORY_PARENT_PREFIX)
    @Override
    public List<Category> loadParentCategory() {
        // 查询所有 parentid为 0的节点 而且 status = 1 状态可用
        List<Category> categoryList = categoryMapper.selectList(
                new LambdaQueryWrapper<Category>()
                        .eq(Category::getParentId, 0)
                        .eq(Category::getStatus, 1)
                        .orderByDesc(Category::getSeq)
        );
        return categoryList;
    }

    /**
     * 新增商品分类
     * Caching 可用有一次干多个动作
     * Cacheable[] cacheable() default {}; 增加缓存
     * CachePut[] put() default {}; 先删除后增加
     * CacheEvict[] evict() default {};  删除
     * 注意 DB的修改要主动去删除缓存. 删除全部相关的缓存
     *
     * @param category
     * @return
     */
    @Caching(evict = {
            @CacheEvict(key = CategoryConstant.CATEGORY_PREFIX),
            @CacheEvict(key = CategoryConstant.CATEGORY_PARENT_PREFIX)
    })
    @Override
    public boolean save(Category category) {
        log.info("新增商品分类{}", JSON.toJSONString(category));
        //设置与MYSQL 约束的 default 属性
        category.setUpdateTime(new Date());
        category.setRecTime(new Date());
        category.setShopId(1L);
        // 先判断是否选中了 父类
        Long parentId = category.getParentId();
        if (parentId == 0L || parentId == null) {
            category.setParentId(0L);
            category.setGrade(1);
        } else {
            // 如果有父类id先判断id是否合法,在MYSQL中存在
            Category parentCategory = categoryMapper.selectById(parentId);
            if (ObjectUtils.isEmpty(parentCategory)) {
                log.error("数据库中没有id{}的父级", parentId);
                throw new IllegalArgumentException("查询分类表数据库, parentId" + parentId + "不存在在");
            }
            //有父id都是 二级
            category.setGrade(2);
        }
        return categoryMapper.insert(category) > 0;
    }


    /**
     * 修改分类数据
     *
     * @param category
     * @return
     */
    @Caching(evict = {
            @CacheEvict(key = CategoryConstant.CATEGORY_PREFIX),
            @CacheEvict(key = CategoryConstant.CATEGORY_PARENT_PREFIX)
    })
    @Override
    public boolean updateById(Category category) {
        log.info("修改商品分类{}", JSON.toJSONString(category));
        return categoryMapper.updateById(category) > 0;
    }

    /**
     * 获得一个分类对象数据
     *
     * @param id
     * @return
     */
    @Caching(evict = {
            @CacheEvict(key = CategoryConstant.CATEGORY_PREFIX),
            @CacheEvict(key = CategoryConstant.CATEGORY_PARENT_PREFIX)
    })
    @Override
    public Category getById(Serializable id) {
        return categoryMapper.selectById(id);
    }

    /**
     * 删除商品分类
     *
     * @param id
     * @return
     */
    @Caching(evict = {
            @CacheEvict(key = CategoryConstant.CATEGORY_PREFIX),
            @CacheEvict(key = CategoryConstant.CATEGORY_PARENT_PREFIX)
    })
    @Override
    public boolean removeById(Serializable id) {
        log.info("删除商品分类", JSON.toJSONString(id));
        return categoryMapper.deleteById(id) > 0;
    }


    /**
     * 查询所有的分类子节点
     *
     * @return
     */
    @Override
    public List<CategoryVo> loadAllSubCategorys() {
        //0. return data

        // 查询所有的 分类的二级节点
        //1.查询分类表
        //这里只考虑二层,而没有考虑多层级遍历组装
        List<Category> categoryList = categoryMapper.selectList(new LambdaQueryWrapper<Category>()
                .eq(Category::getGrade, 2)
        );
        if (CollectionUtils.isEmpty(categoryList)) {
            return Collections.emptyList();
        }
        //2.有数据就要组装数据
        List<CategoryVo> categoryVos = new ArrayList<CategoryVo>(categoryList.size() * 2);
        //3.组装数据
        categoryList.forEach(category -> {
            CategoryVo vo = new CategoryVo();
            vo.setCategoryId(category.getCategoryId());
            vo.setCategoryName(category.getCategoryName());
            vo.setPic(category.getPic());
            categoryVos.add(vo);
        });

        return categoryVos;
    }
}
